const spawn = require("child_process").spawn;
// const { WebSocketServer } = require("@clusterws/cws");
const { WebSocketServer } = require("ws");

module.exports = class MicrophoneServer {
  constructor({ server }) {
    const path = `/microphone`;
    logger.info(`Microphone websocker server starting`, path);
    const wss = new WebSocketServer(
      {
        noServer: true,
        path,
      },
      () => {
        logger.info(`Microphone websocker server started`, path);
      }
    );

    server.on("upgrade", (request, socket, head) => {
      if (request.url === path)
        wss.handleUpgrade(request, socket, head, (ws) => {
          wss.emit("connection", ws, request);
        });
    });

    this.wss = wss;

    wss.on("connection", (socket) => {
      logger.info(`客户端已连接  Microphone Websocket Server`);
      socket.on("close", () => {
        if (wss.clients.length === 0) {
          this.close();
        }
      });

      this.open();
    });

    wss.on("error", (err) => {
      logger.error(err);
    });
  }

  async open() {
    logger.info(`Microphone start`);
    if (this.streamer) {
      logger.info(`Microphone ffmpeg streamer already open`);
      await this.close();
    }
    
    try {
      this.streamer = ffmpeg();
      this.streamer.stdout.on("data", (data) => {
        this.broadcastStream(data);
      });
      
      this.streamer.on('error', (error) => {
        logger.error(`Microphone FFmpeg进程错误: ${error.message}`);
        this.handleFFmpegError(error);
      });
      
    } catch (error) {
      logger.error(`启动Microphone FFmpeg失败: ${error.message}`);
    }
  }

  handleFFmpegError(error) {
    logger.warn('尝试重启 Microphone FFmpeg 进程');
    this.close();
    
    // 2秒后重试
    setTimeout(() => {
      if (this.wss.clients.size > 0) {
        this.open();
      }
    }, 2000);
  }

  async close() {
    if (this.streamer) {
      logger.info(`Microphone ffmpeg streamer killing`);
      
      return new Promise((resolve) => {
        const cleanup = () => {
          this.streamer = undefined;
          resolve();
        };

        try {
          // 使用SIGTERM而不是SIGHUP
          this.streamer.kill("SIGTERM");
          
          // 设置超时，如果进程不退出则强制杀死
          const killTimeout = setTimeout(() => {
            logger.warn('Microphone FFmpeg进程未正常退出，强制终止');
            try {
              this.streamer.kill('SIGKILL');
            } catch (e) {
              logger.debug('强制终止Microphone FFmpeg失败:', e.message);
            }
            cleanup();
          }, 3000);

          this.streamer.on('close', () => {
            clearTimeout(killTimeout);
            cleanup();
          });
          
          this.streamer.on('error', () => {
            clearTimeout(killTimeout);
            cleanup();
          });
          
        } catch (error) {
          logger.warn(`停止Microphone FFmpeg进程时出错: ${error.message}`);
          cleanup();
        }
      });
    }
  }

  sendBinary(socket, frame) {
    if (socket.buzy) return;
    socket.buzy = true;
    socket.buzy = false;

    socket.send(frame, { binary: true }, function ack() {
      socket.buzy = false;
    });
  }

  broadcast(action, payload) {
    this.wss.clients.forEach((socket) =>
      socket.send(JSON.stringify({ action, payload }))
    );
  }

  broadcastStream(data) {
    this.wss.clients.forEach((socket) => {
      this.sendBinary(socket, data);
    });
  }
};

const ffmpeg = function () {
  const args = [
    "-f", "alsa",
    "-ar", "16000",
    "-ac", "1",
    "-i", "default",
    "-c:a", "mp3",
    "-f", "mp3",
    "-avoid_negative_ts", "make_zero",  // 避免负时间戳
    "-fflags", "+genpts",              // 生成时间戳
    "-"
  ];
  
  logger.debug(`启动Microphone FFmpeg: ffmpeg ${args.join(' ')}`);
  
  const streamer = spawn("ffmpeg", args, {
    stdio: ['pipe', 'pipe', 'pipe'],  // 明确指定stdio配置
    detached: false  // 不创建新的进程组
  });

  streamer.on("close", (code, signal) => {
    logger.info(`Microphone ffmpeg close - code: ${code}, signal: ${signal}`);
  });
  
  streamer.on("error", (error) => {
    logger.error(`Microphone ffmpeg spawn error: ${error.message}`);
  });

  streamer.stderr.on("data", (data) => {
    const stderrOutput = data.toString();
    // 只记录重要的错误信息
    if (stderrOutput.includes('Error') || stderrOutput.includes('error') || 
        stderrOutput.includes('failed') || stderrOutput.includes('Invalid')) {
      logger.warn(`Microphone ffmpeg stderr: ${stderrOutput.trim()}`);
    }
  });

  return streamer;
};
